/*
 * $Id: $
 */
package org.rcgwt.client.ui.grid.internal;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.rcgwt.client.ui.grid.internal.model.IColumnModel;
import org.rcgwt.client.ui.grid.internal.model.IElementModel;
import org.rcgwt.client.ui.grid.internal.model.IElementModelDelta;
import org.rcgwt.client.ui.grid.internal.model.IGridEventManager;
import org.rcgwt.client.ui.grid.internal.model.IGridModel;
import org.rcgwt.client.ui.grid.internal.model.IGroupModel;
import org.rcgwt.client.ui.grid.internal.model.IHeaderModel;
import org.rcgwt.client.ui.grid.internal.model.IRowModel;
import org.rcgwt.client.ui.grid.internal.model.ITitleCellModel;
import org.rcgwt.client.ui.grid.internal.model.ITitleRowModel;
import org.rcgwt.client.ui.grid.internal.model.IViewModel;
import org.rcgwt.client.ui.grid.internal.model.IViewModelElements;
import org.rcgwt.client.ui.grid.model.IColumn;
import org.rcgwt.client.ui.grid.model.IGridWidget;
import org.rcgwt.client.ui.grid.model.IGroup;
import org.rcgwt.client.ui.grid.model.IGroupDataModel;
import org.rcgwt.client.ui.grid.provider.IColumnProvider;

import com.google.gwt.dom.client.Element;

/**
 * 
 * @author Olivier Oeuillot (latest modification by $Author: $)
 * @version $Revision: $ $Date: $
 */
public class GridModel extends AbstractElementModel implements IGridModel {

	private final Map<Integer, IRowModel> rowModelsByIndex = new HashMap<Integer, IRowModel>();

	private final IGridWidget gridWidget;

	private final IRenderedIndexRecorder<IRowModel, IGroupModel> rowRenderedIndexRecorder;

	private IColumnModel[] columnModels;

	private IGroupModel[] groupModels;

	private IViewModel[] viewModels;

	private IGridEventManager gridEventManager;

	public GridModel(IGridWidget gridWidget) {
		this.gridWidget = gridWidget;

		rowRenderedIndexRecorder = new RowRenderedIndexRecorder(this);

		fillModel();
	}

	@SuppressWarnings("boxing")
	private void fillModel() {
		// Les groupes !
		IGroupDataModel groupDataModel = gridWidget.getGroupDataModel();
		Iterator<Integer> itGroup = groupDataModel.getGroupModelIndexes(0, -1);

		List<IGroupModel> gms = new ArrayList<IGroupModel>();
		for (; itGroup.hasNext();) {
			int groupModelIndex = itGroup.next();
			IGroup group = groupDataModel.getGroupByIndex(groupModelIndex);

			IGroupModel groupModel = new GroupModel(this, group,
					groupModelIndex);

			gms.add(groupModel);
		}

		groupModels = gms.toArray(new IGroupModel[gms.size()]);

		// Les colonnes

		IColumnProvider columnProvider = gridWidget.getColumnProvider();
		Iterator<Integer> itColumn = columnProvider.getColumnModelIndexes();

		boolean sortable = false;

		List<IColumnModel> cms = new ArrayList<IColumnModel>();
		for (; itColumn.hasNext();) {
			int columnModelIndex = itColumn.next();

			IColumn column = columnProvider
					.getColumnByModelIndex(columnModelIndex);

			IColumnModel columnModel = new ColumnModel(this, column,
					columnModelIndex);

			cms.add(columnModel);

			sortable |= column.isSortable();
		}

		columnModels = cms.toArray(new IColumnModel[cms.size()]);

		// La vue

		ViewModelElements viewModel = new ViewModelElements(0, this,
				IViewModel.HORIZONTAL_SCROLLBAR | IViewModel.VERTICAL_SCROLLBAR);
		viewModels = new IViewModel[] { viewModel };

		HeaderModel headerModel = new HeaderModel(viewModel, 0,
				IHeaderModel.Position.TOP);
		viewModel.setHeaders(new IHeaderModel[] { headerModel });

		TitleRowModel titleRowModel = new TitleRowModel(0, headerModel,
				sortable);
		headerModel.setTitleRowModels(titleRowModel,
				new ITitleRowModel[] { titleRowModel });

		Iterator<Integer> itTitleColumn = columnProvider
				.getColumnModelIndexes(titleRowModel.getModelIndex());

		List<ITitleCellModel> tcs = new ArrayList<ITitleCellModel>();
		for (; itTitleColumn.hasNext();) {
			int columnModelIndex = itTitleColumn.next();

			ITitleCellModel columnModel = new TitleCellModel(cms
					.get(columnModelIndex), titleRowModel);

			tcs.add(columnModel);
		}

		titleRowModel.setTitleCellModels(tcs.toArray(new ITitleCellModel[tcs
				.size()]));

	}

	@Override
	public IGridModel getGridModel() {
		return this;
	}

	@Override
	protected IElementModelDelta<?> getModelElementDelta() {
		if (gridEventManager == null) {
			gridEventManager = gridWidget.getGridModelController()
					.getGridEventManager(gridWidget);
		}
		return gridEventManager.getGridModelDelta();
	}

	@SuppressWarnings("boxing")
	@Override
	public IRowModel searchRowModel(int rowModelIndex) {
		IRowModel rowModel = rowModelsByIndex.get(rowModelIndex);

		return rowModel;
	}

	@SuppressWarnings("boxing")
	@Override
	public void registerRowModel(IRowModel rowModel) {
		rowModelsByIndex.put(rowModel.getModelIndex(), rowModel);
	}

	@Override
	public IElementModel getParent() {
		return null;
	}

	@Override
	public IGridWidget getGridWidget() {
		return gridWidget;
	}

	@Override
	public IColumnModel[] listColumnModels() {
		return columnModels;
	}

	@Override
	public IGroupModel[] listGroupModels() {
		return groupModels;
	}

	@Override
	public IViewModel[] listViewModels() {
		return viewModels;
	}

	@Override
	public Type getType() {
		return Type.GRID;
	}

	@Override
	public IRenderedIndexRecorder<IRowModel, IGroupModel> getRowRenderedIndexRecorder() {
		return rowRenderedIndexRecorder;
	}

	@Override
	public IElementModel findElementModel(Element element) {

		for (IViewModel viewModel : listViewModels()) {

			IViewModelElements viewModelElements = viewModel
					.getViewModelElements();

			IElementModel elementModel = viewModelElements.findElementModel(
					viewModel, element);

			if (elementModel != null) {
				return elementModel;
			}
		}

		Element root = getGridWidget().getElement();
		for (Element et = element; et != null; et = et.getParentElement()) {
			if (et != root) {
				continue;
			}

			return this;
		}

		return null;
	}

	@Override
	public IViewModel findViewModel(Element element) {

		for (IViewModel viewModel : listViewModels()) {

			IViewModelElements viewModelElements = viewModel
					.getViewModelElements();

			IElementModel elementModel = viewModelElements.findElementModel(
					viewModel, element);

			if (elementModel != null) {
				return viewModel;
			}
		}

		return null;
	}
}
